home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / test / checkers.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-09  |  36.3 KB  |  1,370 lines

  1. //
  2. // "$Id: checkers.cxx,v 1.9.2.3 1999/08/09 14:38:40 mike Exp $"
  3. //
  4. // Checkers game for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Hours of fun: the FLTK checkers game!
  7. // Based on a very old algorithim, but it still works!
  8. //
  9. // Copyright 1998-1999 by Bill Spitzak and others.
  10. //
  11. // This library is free software; you can redistribute it and/or
  12. // modify it under the terms of the GNU Library General Public
  13. // License as published by the Free Software Foundation; either
  14. // version 2 of the License, or (at your option) any later version.
  15. //
  16. // This library is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19. // Library General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU Library General Public
  22. // License along with this library; if not, write to the Free Software
  23. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24. // USA.
  25. //
  26. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  27. //
  28.  
  29. const char* copyright = 
  30. "Checkers game\n"
  31. "Copyright (C) 1997 Bill Spitzak    spitzak@d2.com\n"
  32. "Original Pascal code:\n"
  33. "Copyright 1978, Oregon Minicomputer Software, Inc.\n"
  34. "2340 SW Canyon Road, Portland, Oregon 97201\n"
  35. "Written by Steve Poulsen 18-Jan-79\n"
  36. "\n"
  37. "This program is free software; you can redistribute it and/or modify "
  38. "it under the terms of the GNU General Public License as published by "
  39. "the Free Software Foundation; either version 2 of the License, or "
  40. "(at your option) any later version.\n"
  41. "\n"
  42. "This program is distributed in the hope that it will be useful, "
  43. "but WITHOUT ANY WARRANTY; without even the implied warranty of "
  44. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
  45. "GNU General Public License for more details.\n"
  46. "\n"
  47. "You should have received a copy of the GNU Library General Public "
  48. "License along with this library; if not, write to the Free Software "
  49. "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 "
  50. "USA.";
  51.  
  52. // Define FLTK to get the fltk interface
  53. // Define VT100 to get the VT100 interface
  54. // Define both to get a program that takes a -t switch
  55.  
  56. #define FLTK
  57. //#define VT100
  58.  
  59. #include <string.h>
  60. #include <stdlib.h>
  61. #include <stdio.h>
  62. #include <stdarg.h>
  63. #include <ctype.h>
  64. #include <time.h>
  65.  
  66. ////////////////////////////////////////////////////////////////
  67. // The algorithim:
  68.  
  69. int maxevaluate=2500;        // max number of moves to examine on a turn
  70. int maxnodes = 2500;        // maximum number of nodes in search tree
  71. int maxply = 20;        // maximum depth to look ahead
  72. char forcejumps = 1;        // is forced jumps rule in effect?
  73.  
  74. // scoring parameters: (all divided by 5 from original code)
  75. // some signs seem to be backwards, marked them with (-) in comment
  76. const int spiece = 800;        // value of a piece
  77. const int sking = 1200;        // value of a king
  78. const int sadvan = 160;        // value of mypieces/theirpieces-1
  79. // const int smobil = ?        // moves *enemy* can make w/o being jumped
  80. const int sallpin = 80;        // mobil == 0
  81. const int sdeny = 10;        // moves enemy can make that will be jumped
  82. const int spin = 32;        // enemy pieces that have no move except jumped
  83. const int sthreat = -10;    // enemy pieces we can jump if not moved (-)
  84. const int sgrad = 1;        // score of piece positions
  85. const int sback = 10;        // back row occupied so enemy can't make king
  86. const int smoc2 = 200;        // more mobility, more center
  87. const int smoc3 = -8;        // less mobility, less center
  88. const int smoc4 = -80;        // more mobility, less center
  89. const int smode2 = -14;        // less mobility, less denied
  90. const int smode3 = -40;        // more mobility, more denied (-)
  91. const int sdemmo = -20;        // more denied, more moves (-)
  92. const int scent = 10;        // pieces in center
  93. const int skcent = 100;        // kings in center
  94.  
  95. const int depthpenalty=4;    // guess
  96. const int noise=2;        // values less or eq to this apart are eq
  97.  
  98. // const int sattackking = 4;    // not used
  99. // const int sattackpiece = 3;
  100.  
  101. struct node {
  102.   node *father;
  103.   node *son;        // best son
  104.   node *brother;    // next brother
  105.   short int value;    // value of this board position to player making move
  106.   unsigned char from,to; // the move to reach this board
  107.   long int jump;    // bit map of locations jumped
  108.   unsigned char mobil;
  109.   unsigned char deny;
  110.   unsigned char pin;
  111.   unsigned char threat;
  112.   short int gradient;
  113.   unsigned who:1;    // 0 = black's move, 1 = white's move
  114.   unsigned king:1;    // 1 = move causes piece to be kinged
  115.   unsigned back:1;
  116.   unsigned moc2:1;
  117.   unsigned moc3:1;
  118.   unsigned moc4:1;
  119.   unsigned mode2:1;
  120.   unsigned mode3:1;
  121.   unsigned demmo:1;
  122. };
  123.  
  124. int nodes;        // count of nodes
  125.  
  126. /*    Board positions:    Border positions:
  127.  
  128.           WHITE          00  01  02  03  04
  129.       05  06  07  08    04  XX  XX  XX  XX
  130.     09  10  11  12          XX  XX  XX  XX  13
  131.       14  15  16  17    13  XX  XX  XX  XX
  132.     18  19  20  21          XX  XX  XX  XX  22
  133.       23  24  25  26    22  XX  XX  XX  XX
  134.     27  28  29  30          XX  XX  XX  XX  31
  135.       32  33  34  36    31  XX  XX  XX  XX
  136.     36  37  38  39          XX  XX  XX  XX  40
  137.           BLACK        40  41  42  43  44
  138.  
  139. */
  140.  
  141. typedef char piece;
  142.  
  143. // Piece values so that BLACK and WHITE are bit flags:
  144. #define EMPTY 0
  145. #define BLACK 1
  146. #define WHITE 2
  147. #define KING 4
  148. #define BLACKKING 5
  149. #define WHITEKING 6
  150. #define BLUE 8
  151.  
  152. const piece flip[9] = {
  153.   EMPTY, WHITE, BLACK, 0, 0, WHITEKING, BLACKKING, 0, BLUE};
  154.  
  155. const int offset[9][4] = {    // legal move directions
  156.   {0,0,0,0},
  157.   {-5,-4,0,0},
  158.   {4,5,0,0},
  159.   {0,0,0,0},
  160.   {0,0,0,0},
  161.   {4,5,-4,-5},
  162.   {4,5,-4,-5},
  163.   {0,0,0,0},
  164.   {0,0,0,0}
  165. };
  166.  
  167. piece b[45];        // current board position being considered
  168.  
  169. int evaluated;        // number of moves evaluated this turn
  170.  
  171. char centralsquares[45];
  172. char is_protected[45];
  173.  
  174. piece flipboard[45];    // swapped if enemy is black
  175. piece *tb;        // pointer to real or swapped board
  176. #define FRIEND BLACK
  177. #define FRIENDKING BLACKKING
  178. #define ENEMY WHITE
  179. #define ENEMYKING WHITEKING
  180.  
  181. char check(int target,int direction) {
  182.   // see if enemy at target can be jumped from direction by our piece
  183.   int dst = target-direction;
  184.   if (tb[dst]) return(0);
  185.   int src = target+direction;
  186.   if (tb[src] == FRIENDKING);
  187.   else if (direction < 0 || tb[src] != FRIEND) return(0);
  188.   piece a = tb[target]; piece b = tb[src];
  189.   tb[target] = EMPTY; tb[src] = EMPTY;
  190.   int safe =
  191.     (tb[src-4]&FRIEND && tb[src-8]&ENEMY
  192.      ||tb[src-5]&FRIEND && tb[src-10]&ENEMY
  193.      ||tb[dst-4]&ENEMY && !tb[dst+4]
  194.      ||tb[dst-5]&ENEMY && !tb[dst+5]
  195.      ||tb[src+4]&FRIEND && tb[src+8]==ENEMYKING
  196.      ||tb[src+5]&FRIEND && tb[src+10]==ENEMYKING
  197.      ||tb[dst+4]==ENEMYKING && !tb[dst-4]
  198.      ||tb[dst+5]==ENEMYKING && !tb[dst-5]);
  199.   tb[target] = a; tb[src] = b;
  200.   return(safe);
  201. }
  202.  
  203. int deniedmoves,undeniedmoves;
  204. void analyzemove(int direction,int src) {
  205.   int target = src+direction;
  206.   if (!tb[target]) {
  207.     if (!tb[target+direction]) is_protected[target] = 1;
  208.     piece a = tb[src]; tb[src] = EMPTY;
  209.     if (check(target,4) || check(target,5) ||
  210.     check(target,-4) || check(target,-5) ||
  211.     (tb[src+4]&ENEMY && check(src+4,4)) ||
  212.     (tb[src+5]&ENEMY && check(src+5,5)) ||
  213.     (tb[src-4]&ENEMY && check(src-4,-4)) ||
  214.     (tb[src-5]&ENEMY && check(src-5,-5)))
  215.       deniedmoves++;
  216.     else undeniedmoves++;
  217.     tb[src] = a;
  218.   }
  219. }
  220.  
  221. void evaluateboard(node *n,int print) {
  222.  
  223.   if (!n->who) tb = b;    // move was black's
  224.   else {
  225.     for (int i=0; i<45; i++) flipboard[44-i] = flip[b[i]];
  226.     tb = flipboard;
  227.   }
  228.  
  229.   memset(is_protected,0,sizeof(is_protected));
  230.   int friendpieces = 0;
  231.   int enemypieces = 0;
  232.   int friendkings = 0;
  233.   int enemykings = 0;
  234.   int friendkcent = 0;
  235.   int friendcent = 0;
  236.   int enemykcent = 0;
  237.   int enemycent = 0;
  238.   n->mobil = n->deny = n->pin = n->threat = 0;
  239.  
  240.   int i;
  241.   for (i=5; i<40; i++) switch(tb[i]) {
  242.   case ENEMYKING:
  243.     enemykings++;
  244.     enemykcent += centralsquares[i];
  245.     deniedmoves = 0;
  246.     undeniedmoves = 0;
  247.     if (i>8) {
  248.       analyzemove(-4,i);
  249.       analyzemove(-5,i);
  250.     }
  251.     goto J1;
  252.   case ENEMY:
  253.     deniedmoves = 0;
  254.     undeniedmoves = 0;
  255.   J1:    enemypieces++;
  256.     enemycent += centralsquares[i];
  257.     if (i<36) {
  258.       analyzemove(4,i);
  259.       analyzemove(5,i);
  260.     }
  261.     if (deniedmoves && !undeniedmoves) n->pin++;
  262.     n->deny += deniedmoves;
  263.     n->mobil += undeniedmoves;
  264.     break;
  265.   case FRIENDKING:
  266.     friendkings++;
  267.     friendkcent += centralsquares[i];
  268.     if (tb[i+4]&ENEMY && !tb[i+8] && !(tb[i+4]==ENEMYKING && !tb[i-4]))
  269.       n->threat++;
  270.     if (tb[i+5]&ENEMY && !tb[i+10] && !(tb[i+5]==ENEMYKING && !tb[i-5]))
  271.       n->threat++;
  272.   case FRIEND:
  273.     friendpieces++;
  274.     friendcent += centralsquares[i];
  275.     if (tb[i-4]&ENEMY && !tb[i-8] && tb[i+4]) n->threat++;
  276.     if (tb[i-5]&ENEMY && !tb[i-10] && tb[i+5]) n->threat++;
  277.     break;
  278.   }
  279.  
  280.   int gradient[40];
  281.   for (i=4; i<9; i++) gradient[i] = tb[i] ? 0 : 32;
  282.   int total = 0;
  283.   for (i=9; i<40; i++) {
  284.     int x = (gradient[i-4]+gradient[i-5])/2;
  285.     if (tb[i]==FRIEND) total += x;
  286.     gradient[i] = (tb[i]&FRIEND || !tb[i] && !is_protected[i]) ? x : 0;
  287.   }
  288.   n->gradient = total;
  289.  
  290.   n->back = tb[39]==FRIEND && tb[37]==FRIEND && !enemykings;
  291.  
  292.   node* f = n->father;
  293.  
  294.   n->moc2 = f->mobil>n->mobil && friendcent>enemycent;
  295.   n->moc3 = f->mobil<=n->mobil && friendcent<enemycent;
  296.   n->moc4 = f->mobil>n->mobil && friendcent<enemycent;
  297.   n->mode2 = f->mobil<=n->mobil && n->deny<f->deny;
  298.   n->mode3 = f->mobil>n->mobil && n->deny>f->deny;
  299.   n->demmo = n->deny>f->deny && f->deny+f->mobil>n->deny+n->mobil;
  300.  
  301.   total =
  302.     spiece    * (friendpieces - enemypieces) +
  303.     (sking-spiece) * (friendkings    - enemykings) +
  304.     //    mobil?
  305.     sdeny    * (n->deny    - f->deny) +
  306.     spin    * (n->pin    - f->pin) +
  307.     sthreat    * (n->threat    - f->threat) +
  308.     sgrad    * (n->gradient    - f->gradient) +
  309.     sback    * (n->back    - f->back) +
  310.     smoc2    * (n->moc2    - f->moc2) +
  311.     smoc3    * (n->moc3    - f->moc3) +
  312.     smoc4    * (n->moc4    - f->moc4) +
  313.     smode2    * (n->mode2    - f->mode2) +
  314.     smode3    * (n->mode3    - f->mode3) +
  315.     sdemmo    * (n->demmo    - f->demmo) +
  316.     scent    * (friendcent    - enemycent) +
  317.     (skcent-scent) * (friendkcent    - enemykcent);
  318.   if (!n->mobil) total += sallpin;
  319.  
  320.   if (!enemypieces) total = 30000;
  321.   else if (friendpieces > enemypieces)
  322.     total += (sadvan*friendpieces)/enemypieces-sadvan;
  323.   else total -= (sadvan*enemypieces)/friendpieces-sadvan;
  324.  
  325.   if (print) {
  326.     printf("\tParent\tNew\tScore\n");
  327.     printf("pieces\t%d\t%d\t%d\n",enemypieces,friendpieces,
  328.        spiece*(friendpieces-enemypieces));
  329.     printf("kings\t%d\t%d\t%d\n",enemykings,friendkings,
  330.        (sking-spiece)*(friendkings-enemykings));
  331.     printf("mobil\t%d\t%d\n",f->mobil,n->mobil);
  332.     printf("deny\t%d\t%d\t%d\n",f->deny,n->deny,sdeny*(n->deny-f->deny));
  333.     printf("pin\t%d\t%d\t%d\n",f->pin,n->pin,spin*(n->pin-f->pin));
  334.     printf("threat\t%d\t%d\t%d\n",f->threat,n->threat,sthreat*(n->threat-f->threat));
  335.     printf("grad\t%d\t%d\t%d\n",f->gradient,n->gradient,sgrad*(n->gradient-f->gradient));
  336.     printf("back\t%d\t%d\t%d\n",f->back,n->back,sback*(n->back-f->back));
  337.     printf("moc2\t%d\t%d\t%d\n",f->moc2,n->moc2,smoc2*(n->moc2-f->moc2));
  338.     printf("moc3\t%d\t%d\t%d\n",f->moc3,n->moc3,smoc3*(n->moc3-f->moc3));
  339.     printf("moc4\t%d\t%d\t%d\n",f->moc4,n->moc4,smoc4*(n->moc4-f->moc4));
  340.     printf("mode2\t%d\t%d\t%d\n",f->mode2,n->mode2,smode2*(n->mode2-f->mode2));
  341.     printf("mode3\t%d\t%d\t%d\n",f->mode3,n->mode3,smode3*(n->mode3-f->mode3));
  342.     printf("demmo\t%d\t%d\t%d\n",f->demmo,n->demmo,sdemmo*(n->demmo-f->demmo));
  343.     printf("cent\t%d\t%d\t%dn",enemycent,friendcent,scent*(friendcent-enemycent));
  344.     printf("kcent\t%d\t%d\t%d\n",enemykcent,friendkcent,skcent*(friendkcent-enemykcent));
  345.     printf("total:\t\t\t%d\n",total);
  346.   }
  347.   else {
  348.     n->value = total;
  349.     evaluated++;
  350.   }
  351. }    // end of evaluateboard
  352.  
  353. // --------------------- Tree management -----------------
  354.  
  355. node *freelist;
  356.  
  357. node *newnode(void) {
  358.   node *n;
  359.   if (freelist) {
  360.     n = freelist;
  361.     freelist = n->brother;
  362.   }
  363.   else n = (node *)malloc(sizeof(node));
  364.   memset(n,0,sizeof(node));
  365.   nodes++;
  366.   return(n);
  367. }
  368.  
  369. void extract(node *n) {
  370.   node* i = n->father;
  371.   if (i) {
  372.     node* j = i->son;
  373.     if (j==n) i->son = n->brother;
  374.     else while (j) {
  375.       i = j; j = j->brother;
  376.       if (j==n) {i->brother = n->brother; break;}
  377.     }
  378.   }
  379.   n->brother = 0;
  380. }
  381.  
  382. void killnode(node *x) {
  383.   if (!x) return;
  384.   node *y;
  385.   for (y = x; ; y = y->brother) {
  386.     nodes--;
  387.     killnode(y->son); y->son = 0;
  388.     if (!y->brother) break;
  389.   }
  390.   y->brother = freelist;
  391.   freelist = x;
  392. }
  393.  
  394. int seed;        // current random number
  395.  
  396. void insert(node *n) {
  397.   int val = n->value;
  398.   node **pp;
  399.   for (pp = &(n->father->son); *pp; pp = &((*pp)->brother)) {
  400.     int val1 = (*pp)->value;
  401.     if (abs(val-val1) <= noise) {
  402.       seed = (seed*13077+5051)%0100000;
  403.       if ((seed & 070) >= 060) break;
  404.     }
  405.     else if (val > val1) break;
  406.   }
  407.   n->brother = *pp;
  408.   *pp = n;
  409. }
  410.  
  411. // --------------------------------------------------------------
  412.  
  413. void movepiece(node* f, int i, node* jnode) {
  414.   static char jumphappened;
  415.  
  416.   for (int k=0; k<4; k++) {
  417.     int direction = offset[b[i]][k];
  418.     if (!direction) break;
  419.     int j = i+direction;
  420.     if (b[j] == EMPTY) {
  421.       if (!jnode && (!forcejumps || !f->son || !f->son->jump)) {
  422.     node* n = newnode();
  423.     n->father = f;
  424.     n->who = !f->who;
  425.     n->from = i;
  426.     n->to = j;
  427.     piece oldpiece = b[i]; b[i] = EMPTY;
  428.     if (!(oldpiece&KING) && n->who ? (j>=36) : (j<=8)) {
  429.       n->king = 1;
  430.       b[j] = oldpiece|KING;
  431.     }
  432.     else b[j] = oldpiece;
  433.     evaluateboard(n,0);
  434.     insert(n);
  435.     b[i] = oldpiece; b[j] = EMPTY;
  436.       }
  437.     } else if (((b[j]^b[i])&(WHITE|BLACK))==(WHITE|BLACK) && !b[j+direction]) {
  438.       if (forcejumps && f->son && !f->son->jump) {
  439.     killnode(f->son);
  440.     f->son = 0;
  441.       }
  442.       int jumploc = j;
  443.       j += direction;
  444.       node* n = newnode();
  445.       n->father = f;
  446.       n->who = !f->who;
  447.       n->from = i;
  448.       n->to = j;
  449.       n->jump = (1<<(jumploc-10));
  450.       piece oldpiece = b[i]; b[i] = EMPTY;
  451.       if (!(oldpiece&KING) && n->who ? (j>=36) : (j<=8)) {
  452.     n->king = 1;
  453.     b[j] = oldpiece|KING;
  454.       }
  455.       else b[j] = oldpiece;
  456.       if (jnode) {
  457.     n->from = jnode->from;
  458.     n->jump |= jnode->jump;
  459.     n->king |= jnode->king;
  460.       }
  461.       piece jumpedpiece = b[jumploc];
  462.       b[jumploc] = EMPTY;
  463.       jumphappened = 0;
  464.       movepiece(f,j,n);
  465.       if (forcejumps && jumphappened) killnode(n);
  466.       else {evaluateboard(n,0); insert(n);}
  467.       b[i] = oldpiece; b[j] = EMPTY;
  468.       b[jumploc] = jumpedpiece;
  469.       jumphappened = 1;
  470.     }
  471.   }
  472. }
  473.  
  474. void expandnode(node *f) {
  475.   if (f->son || f->value > 28000) return;    // already done
  476.   piece turn = f->who ? BLACK : WHITE;
  477.   for (int i=5; i<40; i++) if (b[i]&turn) movepiece(f,i,0);
  478.   if (f->son) {
  479.     f->value = -f->son->value;
  480.     if (f->brother) f->value -= depthpenalty;
  481.   }
  482.   else f->value = 30000;
  483. }
  484.  
  485. void makemove(node *n) {
  486.   b[n->to] = b[n->from];
  487.   if (n->king) b[n->to] |= KING;
  488.   b[n->from] = EMPTY;
  489.   if (n->jump) for(int i=0; i<32; i++) {
  490.     if (n->jump & (1<<i)) b[10+i] = EMPTY;
  491.   }
  492. }
  493.  
  494. int didabort(void);
  495.  
  496. int fullexpand(node *f, int level) {
  497.   if (didabort() || nodes > maxnodes-(maxply*10) || evaluated > maxevaluate) return(0);
  498.   expandnode(f);
  499.   if (!f->son) return(1);
  500.   piece oldboard[45];
  501.   memmove(oldboard,b,sizeof(b));
  502.   node* n = f->son;
  503.   if (!n->jump && n->brother) {if (level<1) return(1); level--;}
  504.   int i;
  505.   node* sons[32]; for (i=0; (sons[i++] = n); n = n->brother);
  506.   int ret = 1;
  507.   for (i=0; ret && (n = sons[i++]);) {
  508.     makemove(n);
  509.     ret = fullexpand(n,level);
  510.     memmove(b,oldboard,sizeof(b));
  511.     extract(n);
  512.     insert(n);
  513.   }
  514.   f->value = -f->son->value;
  515.   return(ret);
  516. }
  517.  
  518. int descend(node *f) {
  519.   static int depth;
  520.   if (didabort() || nodes > maxnodes || depth >= maxply) return(0);
  521.   if (f->son) {
  522.     node* n = f->son;
  523.     makemove(n);
  524.     depth++;
  525.     int ret = descend(n);
  526.     depth--;
  527.     extract(n);
  528.     insert(n);
  529.     f->value = -f->son->value;
  530.     return(ret);
  531.   }
  532.   else {expandnode(f); return(1);}
  533. }
  534.  
  535. char debug;
  536.  
  537. node *calcmove(node *root) {    // return best move after root
  538.   expandnode(root);
  539.   if (!root->son) return(0);    // no move due to loss
  540.   if (debug) printf("calcmove() initial nodes = %d\n",nodes);
  541.   evaluated = 0;
  542.   if (root->son->brother) {
  543.     int x;
  544.     for (x = 1; abs(root->value)<28000 && fullexpand(root,x); x++);
  545.     piece saveboard[45]; memmove(saveboard,b,sizeof(b));
  546.     while (abs(root->value)<28000) {
  547.       x = descend(root);
  548.       memmove(b,saveboard,sizeof(b));
  549.       if (!x) break;
  550.     }
  551.   }
  552.   if (debug) printf(" evaluated %d, nodes = %d\n", evaluated, nodes);
  553.   return(root->son);
  554. }
  555.  
  556. // the actual game state ----------------
  557.  
  558. node *root,*undoroot;
  559.  
  560. piece jumpboards[24][45];    // saved boards for undoing jumps
  561. int nextjump;
  562.  
  563. char user;    // 0 = black, 1 = white
  564. char playing;
  565. char autoplay;
  566.  
  567. void newgame(void) {
  568.  
  569.   int n;
  570.   for (n=0; n<5; n++) b[n] = BLUE;
  571.   for (n=5; n<18; n++) b[n] = WHITE;
  572.   for (n=18; n<27; n++) b[n] = EMPTY;
  573.   for (n=27; n<40; n++) b[n] = BLACK;
  574.   for (n=40; n<45; n++) b[n] = BLUE;
  575.   b[13] = b[22] = b[31] = BLUE;
  576.  
  577.   centralsquares[15] = centralsquares[16] =
  578.     centralsquares[19] = centralsquares[20] =
  579.     centralsquares[24] = centralsquares[25] =
  580.     centralsquares[28] = centralsquares[29] = 1;
  581.  
  582.   // set up initial search tree:
  583.   nextjump = 0;
  584.   killnode(undoroot);
  585.   undoroot = root = newnode();
  586.  
  587.   // make it white's move, so first move is black:
  588.   root->who = 1;
  589.   user = 0;
  590.   playing = 1;
  591. }
  592.  
  593. void domove(node* move) {
  594.   if (move->jump) memmove(jumpboards[nextjump++],b,sizeof(b));
  595.   makemove(move);
  596.   extract(move);
  597.   killnode(root->son);
  598.   root->son = move;
  599.   root = move;
  600.   if (debug) evaluateboard(move,1);
  601. }
  602.  
  603. node* undomove() {
  604.   node *n = root;
  605.   if (n == undoroot) return 0; // no more undo possible
  606.   if (n->jump) memmove(b,jumpboards[--nextjump],sizeof(b));
  607.   else {
  608.     b[n->from] = b[n->to];
  609.     if (n->king) b[n->from] &= (WHITE|BLACK);
  610.     b[n->to] = EMPTY;
  611.   }
  612.   root = n->father;
  613.   killnode(n);
  614.   root->son = 0;
  615.   root->value = 0;    // prevent it from thinking game is over
  616.   playing = 1;
  617.   if (root == undoroot) user = 0;
  618.   return n;
  619. }
  620.  
  621. const char _usermoves[] =
  622. "B1D1F1H1A2C2E2G2??B3D3F3H3A4C4E4G4??B5D5F5H5A6C6E6G6??B7D7F7H7A8C8E8G8??";
  623. #define usermoves(x,y) _usermoves[2*((x)-5)+(y)-1]
  624.  
  625. void dumpnode(node *n, int help) {
  626.   int x = n->from;
  627.   int y = n->to;
  628.   if (help) printf("%c%c %c%c\t- ",
  629.            usermoves(x,1),usermoves(x,2),
  630.            usermoves(y,1),usermoves(y,2));
  631.   printf("%s %ss from %c%c to %c%c",
  632.      n->who ? "White" : "Black",
  633.      n->jump ? "jump" : "move",
  634.      usermoves(x,1),usermoves(x,2),
  635.      usermoves(y,1),usermoves(y,2));
  636.   if (n->jump) {
  637.     for (int i=0; i<32; i++) if (n->jump & (1<<i))
  638.       printf(", %c%c",usermoves(10+i,1),usermoves(10+i,2));
  639.     printf(" removed");
  640.   }
  641.   printf(" (%+d).\n",n->value);
  642. }
  643.  
  644. int abortflag;
  645.  
  646. ////////////////////////////////////////////////////////////////
  647. // VT100 Interface:
  648. #ifdef VT100
  649.  
  650. void positioncursor(int i) {
  651.   printf("\033[%d;%dH",
  652.      usermoves(i,2)-'0'+1,
  653.      2*(usermoves(i,1)-'A')+1);
  654. }
  655.  
  656. void outpiecename(piece n) {
  657.   printf(n&BLACK ? "\033[1;7m" : "\033[1m");
  658.   putchar(" BW??BW??"[n]);
  659.   putchar(" BW??KK??"[n]);
  660.   printf("\033[0m");
  661. }
  662.  
  663. void VT100board(void) {
  664.   printf("\033<\033[H\033[J\033[10r");
  665.   int l = 0;
  666.   puts(" A B C D E F G H");
  667.   for (int i=0; i<4; i++) {
  668.     int j = 9*i+5;
  669.     int k;
  670.     for (k=0; k<4; k++) {
  671.       printf("\033[7m  \033[0m");
  672.       outpiecename(b[j+k]);
  673.     }
  674.     l++;
  675.     printf("%d\n",l);
  676.     j += 4;
  677.     for (k=0; k<4; k++) {
  678.       outpiecename(b[j+k]);
  679.       printf("\033[7m  \033[0m");
  680.     }
  681.     l++;
  682.     printf("%d\n",l);
  683.   }
  684. }
  685.  
  686. void VT100move(node *n, int) {
  687.   if (!n) return;
  688.   printf("\0337");
  689.   positioncursor(n->from);
  690.   outpiecename(b[n->from]);
  691.   positioncursor(n->to);
  692.   outpiecename(b[n->to]);
  693.   if (n->jump) for(int i=0; i<32; i++) {
  694.     if (n->jump & (1<<i)) {
  695.       positioncursor(10+i);
  696.       outpiecename(b[10+i]);
  697.     }
  698.   }
  699.   printf("\0338");
  700. }
  701.  
  702. int decode(char *m) {
  703.   int i;
  704.   for(i=5; i<=40; i++)
  705.     if (toupper(m[0])==usermoves(i,1) && m[1]==usermoves(i,2)) return(i);
  706.   return(0);
  707. }
  708.  
  709. #include <signal.h>
  710.  
  711. static void sigint(...) {
  712.   abortflag = 1;
  713.   signal(SIGINT,sigint);
  714. }
  715.  
  716. void fixexit(int x) {
  717.   printf("\0337\033[r\0338");
  718.   exit(x);
  719. }
  720.  
  721. // Returns a son, or 0 if no move specified, or root to cause "help"
  722. node *getusermove(void) {
  723.   int i,j;
  724.   node *t;
  725.   char line[100],*m1,*m2;
  726.  
  727.   if (playing)
  728.     printf("\033[1m%s's move?\033[0m ",root->who ? "Black" : "White");
  729.   else
  730.     printf("\033[1mCommand?\033[0m ");
  731.   abortflag = 0;
  732.   if (!gets(line)) {
  733.     putchar('\n');
  734.     if (feof(stdin)) fixexit(0);
  735.     return 0;
  736.   }
  737.   for (m1 = line; *m1 && *m1<=' '; m1++);
  738.   if (!*m1) return(0);
  739.   m2 = m1+1;
  740.   if (*m2) m2++;
  741.   for (; *m2 && *m2<'0'; m2++);
  742.   if (playing && m1[1]>='0' && m1[1]<='9') {
  743.     i = decode(m1);
  744.     j = decode(m2);
  745.     if (i && j) for (t = root->son; t; t = t->brother)
  746.       if (t->from == i && t->to == j) return(t);
  747.     puts("Valid moves are:");
  748.     m1[0] = 'L';
  749.   }
  750.   switch(toupper(m1[0])) {
  751.   case 0: return(0);
  752.   case 'A':
  753.     if (playing) autoplay = 1;
  754.     return(root);
  755.   case 'C':
  756.     puts(copyright);
  757.     break;
  758.   case 'D':
  759.     debug = !debug;
  760.     printf("Debug is now %s.", debug ? "on" : "off");
  761.     break;
  762.   case 'F':
  763.     forcejumps = !forcejumps;
  764.     printf("Forced jumps rule is now %s.",forcejumps ? "on" : "off");
  765.     killnode(root->son); root->son = 0;
  766.     return(0);
  767.   case 'L':
  768.     expandnode(root);
  769.     if (playing) for (t = root->son; t; t = t->brother) dumpnode(t,1);
  770.     break;
  771.   case 'M':
  772.     return(playing ? root : 0);
  773.   case 'N':
  774.     newgame();
  775.     VT100board();
  776.     return(0);
  777.   case 'P':
  778.     printf("I expect the following moves:\n");
  779.     for (t = root->son; t; t = t->son) dumpnode(t,0);
  780.     break;
  781.   case 'Q':
  782.     fixexit(0);
  783.   case 'R':
  784.     VT100board();
  785.     break;
  786.   case 'S':
  787.     user = !user;
  788.     return(root);
  789.   case 'U':
  790.     VT100move(undomove(),1);
  791.     VT100move(undomove(),1);
  792.     return(0);
  793.   case '+':
  794.     maxevaluate = maxnodes = 2*maxevaluate;
  795.     goto J2;
  796.   case '-':
  797.     if (maxevaluate > 1)
  798.       maxevaluate = maxnodes = maxevaluate/2;
  799.   J2: printf("Moves evaluated set to %d.",maxevaluate);
  800.     break;
  801.   default:
  802.     puts(
  803.      "A(utoplay)\n"
  804.      "C(opyright)\n"
  805.      "D(ebug on/off)\n"
  806.      "F(orce jumps rule on/off)\n"
  807.      "L(ist legal moves)\n"
  808.      "M(ake a move for me)\n"
  809.      "N(ew game)\n"
  810.      "P(redict next few moves)\n"
  811.      "Q(uit)\n"
  812.      "R(edraw screen)\n"
  813.      "S(witch sides)\n"
  814.      "U(ndo)\n"
  815.      "+    - smarter\n"
  816.      "-    - stupider");
  817.     expandnode(root);
  818.     for (t = root->son; t; t = t->brother) dumpnode(t,1);
  819.   }
  820.   return(0);
  821. }
  822.  
  823. int VT100main() {
  824.   signal(SIGINT,sigint);
  825.   VT100board();
  826.   for (;;) {
  827.     if (playing) {
  828.       expandnode(root);
  829.       if (!root->son) {
  830.     printf("%s has no move.  Game over.",root->who ? "Black" : "White");
  831.     playing = autoplay = 0;
  832.       }
  833.     }
  834.     node* move;
  835.     if (playing && (autoplay || root->who == user)) {
  836.       move = calcmove(root);
  837.       if (move->value <= -30000) {
  838.      printf("%s resigns.", move->who ? "White" : "Black");
  839.      move = 0;
  840.      playing = autoplay = 0;
  841.       }
  842.     } else {
  843.       move = getusermove();
  844.       if (move == root) move = calcmove(root);
  845.     }
  846.     if (move) {
  847.       dumpnode(move,0);
  848.       domove(move);
  849.       VT100move(move,0);
  850.     }
  851.   }
  852. }
  853.  
  854. #endif
  855.  
  856. ////////////////////////////////////////////////////////////////
  857. // fltk interface:
  858. #ifdef FLTK
  859.  
  860. #include <FL/Fl.H>
  861. #include <FL/Fl_Double_Window.H>
  862. #include <FL/Fl_Bitmap.H>
  863. #include <FL/fl_draw.H>
  864. #include <FL/Fl_Menu_Item.H>
  865. #include <FL/fl_ask.H>
  866.  
  867. //----------------------------------------------------------------
  868. // old 4-level NeXT images have been seperated into bitmaps so they
  869. // can be drawn with arbitrary colors and real transparency.  This is
  870. // rather tedious and perhaps fltk should provide a direct support
  871. // to do this:
  872.  
  873. #include "black_1.xbm"
  874. #include "black_2.xbm"
  875. #include "black_3.xbm"
  876. #include "black_4.xbm"
  877. #include "white_1.xbm"
  878. #include "white_2.xbm"
  879. #include "white_3.xbm"
  880. #include "white_4.xbm"
  881. #include "blackking_1.xbm"
  882. #include "blackking_2.xbm"
  883. #include "blackking_3.xbm"
  884. #include "blackking_4.xbm"
  885. #include "whiteking_1.xbm"
  886. #include "whiteking_2.xbm"
  887. #include "whiteking_3.xbm"
  888. #include "whiteking_4.xbm"
  889.  
  890. Fl_Bitmap *bm[4][4];
  891.  
  892. void make_bitmaps() {
  893.   if (bm[0][0]) return;
  894.   bm[0][0] = new Fl_Bitmap(black_1_bits, black_1_width, black_1_height);
  895.   bm[0][1] = new Fl_Bitmap(black_2_bits, black_1_width, black_1_height);
  896.   bm[0][2] = new Fl_Bitmap(black_3_bits, black_1_width, black_1_height);
  897.   bm[0][3] = new Fl_Bitmap(black_4_bits, black_1_width, black_1_height);
  898.   bm[1][0] = new Fl_Bitmap(white_1_bits, black_1_width, black_1_height);
  899.   bm[1][1] = new Fl_Bitmap(white_2_bits, black_1_width, black_1_height);
  900.   bm[1][2] = new Fl_Bitmap(white_3_bits, black_1_width, black_1_height);
  901.   bm[1][3] = new Fl_Bitmap(white_4_bits, black_1_width, black_1_height);
  902.   bm[2][0] = new Fl_Bitmap(blackking_1_bits, black_1_width, black_1_height);
  903.   bm[2][1] = new Fl_Bitmap(blackking_2_bits, black_1_width, black_1_height);
  904.   bm[2][2] = new Fl_Bitmap(blackking_3_bits, black_1_width, black_1_height);
  905.   bm[2][3] = new Fl_Bitmap(blackking_4_bits, black_1_width, black_1_height);
  906.   bm[3][0] = new Fl_Bitmap(whiteking_1_bits, black_1_width, black_1_height);
  907.   bm[3][1] = new Fl_Bitmap(whiteking_2_bits, black_1_width, black_1_height);
  908.   bm[3][2] = new Fl_Bitmap(whiteking_3_bits, black_1_width, black_1_height);
  909.   bm[3][3] = new Fl_Bitmap(whiteking_4_bits, black_1_width, black_1_height);
  910. }
  911.  
  912. #define ISIZE black_1_width
  913.  
  914. void draw_piece(int which, int x, int y) {
  915.   if (!fl_not_clipped(x,y,ISIZE,ISIZE)) return;
  916.   switch (which) {
  917.   case BLACK: which = 0; break;
  918.   case WHITE: which = 1; break;
  919.   case BLACKKING: which = 2; break;
  920.   case WHITEKING: which = 3; break;
  921.   default: return;
  922.   }
  923.   fl_color(FL_BLACK); bm[which][0]->draw(x, y);
  924.   fl_color(FL_INACTIVE_COLOR); bm[which][1]->draw(x, y);
  925.   fl_color(FL_SELECTION_COLOR); bm[which][2]->draw(x, y);
  926.   fl_color(FL_WHITE); bm[which][3]->draw(x, y);
  927. }
  928.  
  929. //----------------------------------------------------------------
  930.  
  931. class Board : public Fl_Double_Window {
  932.   void draw();
  933.   int handle(int);
  934. public:
  935.   void drag_piece(int, int, int);
  936.   void drop_piece(int);
  937.   void animate(node* move, int backwards);
  938.   void computer_move(int);
  939.   Board(int w, int h) : Fl_Double_Window(w,h) {color(15);}
  940. };
  941.  
  942. #define BOXSIZE 52
  943. #define BORDER 4
  944. #define BOARDSIZE (8*BOXSIZE+BORDER)
  945. #define BMOFFSET 5
  946.  
  947. static int erase_this;  // real location of dragging piece, don't draw it
  948. static int dragging;    // piece being dragged
  949. static int dragx;    // where it is
  950. static int dragy;
  951. static int showlegal;    // show legal moves
  952.  
  953. int squarex(int i) {return (usermoves(i,1)-'A')*BOXSIZE+BMOFFSET;}
  954. int squarey(int i) {return (usermoves(i,2)-'1')*BOXSIZE+BMOFFSET;}
  955.  
  956. void Board::draw() {
  957.   make_bitmaps();
  958.   fl_draw_box(box(),0,0,w(),h(),color());
  959.   fl_color((Fl_Color)10 /*107*/);
  960.   int x; for (x=0; x<8; x++) for (int y=0; y<8; y++) {
  961.     if (!((x^y)&1)) fl_rectf(BORDER+x*BOXSIZE, BORDER+y*BOXSIZE,
  962.                  BOXSIZE-BORDER, BOXSIZE-BORDER);
  963.   }
  964.   fl_color(FL_DARK3 /*FL_GRAY_RAMP+4*/);
  965.   for (x=0; x<9; x++) {
  966.     fl_rectf(x*BOXSIZE,0,BORDER,h());
  967.     fl_rectf(0,x*BOXSIZE,w(),BORDER);
  968.   }
  969.   for (int i = 5; i < 40; i++) if (i != erase_this) {
  970.     draw_piece(b[i], squarex(i), squarey(i));
  971.   }
  972.   if (showlegal) {
  973.     fl_color(FL_WHITE);
  974.     node* n;
  975.     for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
  976.       int x1 = squarex(n->from)+BOXSIZE/2-5;
  977.       int y1 = squarey(n->from)+BOXSIZE/2-5;
  978.       int x2 = squarex(n->to)+BOXSIZE/2-5;
  979.       int y2 = squarey(n->to)+BOXSIZE/2-5;
  980.       fl_line(x1,y1,x2,y2);
  981.       fl_push_matrix();
  982.       fl_mult_matrix(x2-x1,y2-y1,y1-y2,x2-x1,x2,y2);
  983.       fl_begin_polygon();
  984.       fl_vertex(0,0);
  985.       fl_vertex(-.3, .1);
  986.       fl_vertex(-.3, -.1);
  987.       fl_end_polygon();
  988.       fl_pop_matrix();
  989.     }
  990.     int num = 1;
  991.     fl_color(FL_BLACK);
  992.     fl_font(FL_BOLD,10);
  993.     for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
  994.       int x1 = squarex(n->from)+BOXSIZE/2-5;
  995.       int y1 = squarey(n->from)+BOXSIZE/2-5;
  996.       int x2 = squarex(n->to)+BOXSIZE/2-5;
  997.       int y2 = squarey(n->to)+BOXSIZE/2-5;
  998.       char buf[20]; sprintf(buf,"%d",num);
  999.       fl_draw(buf, x1+int((x2-x1)*.85)-3, y1+int((y2-y1)*.85)+5);
  1000.       num++;
  1001.     }
  1002.   }
  1003.   if (dragging) draw_piece(dragging, dragx, dragy);
  1004. }
  1005.  
  1006. // drag the piece on square i to dx dy, or undo drag if i is zero:
  1007. void Board::drag_piece(int i, int dx, int dy) {
  1008.   dy = (dy&-2) | dx&1; // make halftone shadows line up
  1009.   if (i != erase_this) drop_piece(erase_this); // should not happen
  1010.   if (!erase_this) { // pick up old piece
  1011.     dragx = squarex(i); dragy = squarey(i);
  1012.     erase_this = i;
  1013.     dragging = b[i];
  1014.   }
  1015.   if (dx != dragx || dy != dragy) {
  1016.     damage(FL_DAMAGE_ALL, dragx, dragy, ISIZE, ISIZE);
  1017.     damage(FL_DAMAGE_ALL, dx, dy, ISIZE, ISIZE);
  1018.   }
  1019.   dragx = dx;
  1020.   dragy = dy;
  1021. }
  1022.  
  1023. // drop currently dragged piece on square i
  1024. void Board::drop_piece(int i) {
  1025.   if (!erase_this) return; // should not happen!
  1026.   erase_this = 0;
  1027.   dragging = 0;
  1028.   int x = squarex(i);
  1029.   int y = squarey(i);
  1030.   if (x != dragx || y != dragy) {
  1031.     damage(4, dragx, dragy, ISIZE, ISIZE);
  1032.     damage(4, x, y, ISIZE, ISIZE);
  1033.   }
  1034. }
  1035.  
  1036. // show move (call this *before* the move, *after* undo):
  1037. void Board::animate(node* move, int backwards) {
  1038.   if (showlegal) {showlegal = 0; redraw();}
  1039.   if (!move) return;
  1040.   int f = move->from;
  1041.   int t = move->to;
  1042.   if (backwards) {int x = f; f = t; t = x;}
  1043.   int x1 = squarex(f);
  1044.   int y1 = squarey(f);
  1045.   int x2 = squarex(t);
  1046.   int y2 = squarey(t);
  1047.   const int STEPS=35;
  1048.   for (int i=0; i<STEPS; i++) {
  1049.     int x = x1+(x2-x1)*i/STEPS;
  1050.     int y = y1+(y2-y1)*i/STEPS;
  1051.     drag_piece(move->from,x,y);
  1052.     Fl::flush();
  1053.   }
  1054.   drop_piece(t);
  1055.   if (move->jump) redraw();
  1056. }
  1057.  
  1058. int busy; // causes pop-up abort menu
  1059.  
  1060. void message(const char* m, ...) {
  1061.   char buffer[2048];
  1062.   va_list a;
  1063.   va_start(a,m);
  1064.   vsprintf(buffer, m, a);
  1065.   va_end(a);
  1066.   fl_message(buffer);
  1067. }
  1068.  
  1069. void Board::computer_move(int help) {
  1070.   if (!playing) return;
  1071.   cursor(FL_CURSOR_WAIT);
  1072.   Fl::flush();
  1073.   busy = 1; abortflag = 0;
  1074.   node* move = calcmove(root);
  1075.   busy = 0;
  1076.   if (move) {
  1077.     if (!help && move->value <= -30000) {
  1078.       message("%s resigns", move->who ? "White" : "Black");
  1079.       playing = autoplay = 0;
  1080.       cursor(FL_CURSOR_DEFAULT);
  1081.       return;
  1082.     }
  1083.     animate(move,0);
  1084.     domove(move);
  1085.   }
  1086.   expandnode(root);
  1087.   if (!root->son) {
  1088.     message("%s has no move", root->who ? "Black" : "White");
  1089.     playing = autoplay = 0;
  1090.   }
  1091.   if (!autoplay) cursor(FL_CURSOR_DEFAULT);
  1092. }
  1093.  
  1094. extern Fl_Menu_Item menu[];
  1095. extern Fl_Menu_Item busymenu[];
  1096.  
  1097. int Board::handle(int e) {
  1098.   if (busy) {
  1099.     const Fl_Menu_Item* m;
  1100.     switch(e) {
  1101.     case FL_PUSH:
  1102.       m = busymenu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
  1103.       if (m) m->do_callback(this, (void*)m);
  1104.       return 1;
  1105.     case FL_SHORTCUT:
  1106.       m = busymenu->test_shortcut();
  1107.       if (m) {m->do_callback(this, (void*)m); return 1;}
  1108.       return 0;
  1109.     default:
  1110.       return 0;
  1111.     }
  1112.   }
  1113.   node *t, *n;
  1114.   static int deltax, deltay;
  1115.   int dist;
  1116.   const Fl_Menu_Item* m;
  1117.   switch (e) {
  1118.   case FL_PUSH:
  1119.     if (Fl::event_button() > 1) {
  1120.       m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
  1121.       if (m) m->do_callback(this, (void*)m);
  1122.       return 1;
  1123.     }
  1124.     if (playing) {
  1125.       expandnode(root);
  1126.       for (t = root->son; t; t = t->brother) {
  1127.     int x = squarex(t->from);
  1128.     int y = squarey(t->from);
  1129.     if (Fl::event_inside(x,y,BOXSIZE,BOXSIZE)) {
  1130.       deltax = Fl::event_x()-x;
  1131.       deltay = Fl::event_y()-y;
  1132.       drag_piece(t->from,x,y);
  1133.       return 1;
  1134.     }
  1135.       }
  1136.     }
  1137.     return 0;
  1138.   case FL_SHORTCUT:
  1139.     m = menu->test_shortcut();
  1140.     if (m) {m->do_callback(this, (void*)m); return 1;}
  1141.     return 0;
  1142.   case FL_DRAG:
  1143.     drag_piece(erase_this, Fl::event_x()-deltax, Fl::event_y()-deltay);
  1144.     return 1;
  1145.   case FL_RELEASE:
  1146.     // find the closest legal move he dropped it on:
  1147.     dist = 50*50; n = 0;
  1148.     for (t = root->son; t; t = t->brother) if (t->from==erase_this) {
  1149.       int d1 = Fl::event_x()-deltax-squarex(t->to);
  1150.       int d = d1*d1;
  1151.       d1 = Fl::event_y()-deltay-squarey(t->to);
  1152.       d += d1*d1;
  1153.       if (d < dist) {dist = d; n = t;}
  1154.     }
  1155.     if (!n) {drop_piece(erase_this); return 1;} // none found
  1156.     drop_piece(n->to);
  1157.     domove(n);
  1158.     if (showlegal) {showlegal = 0; redraw();}
  1159.     if (n->jump) redraw();
  1160.     computer_move(0);
  1161.     return 1;
  1162.   default:
  1163.     return 0;
  1164.   }
  1165. }
  1166.  
  1167. void quit_cb(Fl_Widget*, void*) {exit(0);}
  1168.  
  1169. int FLTKmain(int argc, char** argv) {
  1170.   Fl::visual(FL_DOUBLE|FL_INDEX);
  1171.   Board b(BOARDSIZE,BOARDSIZE);
  1172.   b.callback(quit_cb);
  1173.   b.show(argc,argv);
  1174.   return Fl::run();
  1175.  
  1176. void autoplay_cb(Fl_Widget*bp, void*) {
  1177.   if (autoplay) {autoplay = 0; return;}
  1178.   if (!playing) return;
  1179.   Board* b = (Board*)bp;
  1180.   autoplay = 1;
  1181.   while (autoplay) {b->computer_move(0); b->computer_move(0);}
  1182. }
  1183.  
  1184. #include <FL/Fl_Box.H>
  1185. Fl_Window *copyright_window;
  1186. void copyright_cb(Fl_Widget*, void*) {
  1187.   if (!copyright_window) {
  1188.     copyright_window = new Fl_Window(400,270,"Copyright");
  1189.     copyright_window->color(FL_WHITE);
  1190.     Fl_Box *b = new Fl_Box(20,0,380,270,copyright);
  1191.     b->labelsize(10);
  1192.     b->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
  1193.     copyright_window->end();
  1194.   }
  1195.   copyright_window->hotspot(copyright_window);
  1196.   copyright_window->set_non_modal();
  1197.   copyright_window->show();
  1198. }
  1199.  
  1200. void debug_cb(Fl_Widget*, void*v) {
  1201.   debug = !debug;
  1202.   ((Fl_Menu_Item*)v)->flags =
  1203.     debug ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
  1204. }
  1205.  
  1206. void forced_cb(Fl_Widget*b, void*v) {
  1207.   forcejumps = !forcejumps;
  1208.   ((Fl_Menu_Item*)v)->flags =
  1209.     forcejumps ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
  1210.   killnode(root->son); root->son = 0;
  1211.   if (showlegal) {expandnode(root); b->redraw();}
  1212. }
  1213.  
  1214. void move_cb(Fl_Widget*pb, void*) {
  1215.   Board* b = (Board*)pb;
  1216.   if (playing) b->computer_move(1);
  1217.   if (playing) b->computer_move(0);
  1218. }
  1219.  
  1220. void newgame_cb(Fl_Widget*b, void*) {
  1221.   showlegal = 0;
  1222.   newgame();
  1223.   b->redraw();
  1224. }
  1225.  
  1226. void legal_cb(Fl_Widget*pb, void*) {
  1227.   if (showlegal == 1) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  1228.   if (!playing) return;
  1229.   expandnode(root);
  1230.   showlegal = 1; ((Board*)pb)->redraw();
  1231. }
  1232.  
  1233. void predict_cb(Fl_Widget*pb, void*) {
  1234.   if (showlegal == 2) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  1235.   if (playing) expandnode(root);
  1236.   showlegal = 2; ((Board*)pb)->redraw();
  1237. }
  1238.  
  1239. void switch_cb(Fl_Widget*pb, void*) {
  1240.   user = !user;
  1241.   ((Board*)pb)->computer_move(0);
  1242. }
  1243.  
  1244. void undo_cb(Fl_Widget*pb, void*) {
  1245.   Board* b = (Board*)pb;
  1246.   b->animate(undomove(),1);
  1247.   b->animate(undomove(),1);
  1248. }
  1249.  
  1250. //--------------------------
  1251.  
  1252. #include <FL/Fl_Slider.H>
  1253. #include <FL/Fl_Value_Output.H>
  1254.  
  1255. Fl_Window *intel_window;
  1256. Fl_Value_Output *intel_output;
  1257.  
  1258. void intel_slider_cb(Fl_Widget*w, void*) {
  1259.   double v = ((Fl_Slider*)w)->value();
  1260.   int n = int(v*v);
  1261.   intel_output->value(n);
  1262.   maxevaluate = maxnodes = n;
  1263. }
  1264.  
  1265. void intel_cb(Fl_Widget*, void*) {
  1266.   if (!intel_window) {
  1267.     intel_window = new Fl_Window(200,25,"Checkers Intelligence");
  1268.     Fl_Slider* s = new Fl_Slider(60,0,140,25);
  1269.     s->type(FL_HOR_NICE_SLIDER);
  1270.     s->minimum(1); s->maximum(500); s->value(50);
  1271.     s->callback(intel_slider_cb);
  1272.     intel_output = new Fl_Value_Output(0,0,60,25);
  1273.     intel_output->value(maxevaluate);
  1274.     intel_window->resizable(s);
  1275.   }
  1276.   intel_window->hotspot(intel_window);
  1277.   intel_window->set_non_modal();
  1278.   intel_window->show();
  1279. }
  1280.  
  1281. //---------------------------
  1282.  
  1283. void stop_cb(Fl_Widget*, void*) {abortflag = 1;}
  1284.  
  1285. void continue_cb(Fl_Widget*, void*) {}
  1286.  
  1287. Fl_Menu_Item menu[] = {
  1288.   {"Autoplay", 'a', autoplay_cb},
  1289.   {"Legal moves", 'l', legal_cb},
  1290.   {"Move for me", 'm', move_cb},
  1291.   {"New game", 'n', newgame_cb},
  1292.   {"Predict", 'p', predict_cb},
  1293.   {"Switch sides", 's', switch_cb},
  1294.   {"Undo", 'u', undo_cb, 0, FL_MENU_DIVIDER},
  1295.   {"Forced jumps rule", 'f', forced_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
  1296.   {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  1297.   {"Intelligence...", 'i', intel_cb, 0, FL_MENU_DIVIDER},
  1298.   {"Copyright", 'c', copyright_cb},
  1299.   {"Quit", 'q', quit_cb},
  1300.   {0}};
  1301.  
  1302. Fl_Menu_Item busymenu[] = {
  1303.   {"Stop", '.', stop_cb},
  1304.   {"Autoplay", 'a', autoplay_cb},
  1305.   {"Continue", 0, continue_cb},
  1306.   {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  1307.   {"Intelligence...", 'i', intel_cb},
  1308.   {"Copyright", 'c', copyright_cb},
  1309.   {"Quit", 'q', quit_cb},
  1310.   {0}};
  1311.  
  1312. #endif
  1313.  
  1314. ////////////////////////////////////////////////////////////////
  1315. // parts shared by both interface:
  1316.  
  1317. #ifdef FLTK
  1318. #ifdef VT100
  1319. #define BOTH
  1320. #endif
  1321. #endif
  1322.  
  1323. #ifdef BOTH
  1324. int terminal;
  1325. int arg(int, char **argv, int &i) {
  1326.   if (argv[i][1] == 't') {terminal = 1; i++; return 1;}
  1327.   return 0;
  1328. }
  1329. #endif
  1330.  
  1331. int didabort(void) {
  1332. #ifdef FLTK
  1333. #ifdef BOTH
  1334.   if (!terminal)
  1335. #endif
  1336.     Fl::check();
  1337. #endif
  1338.   if (abortflag) {
  1339.     autoplay = 0;
  1340.     abortflag = 0;
  1341.     return 1;
  1342.   }
  1343.   return(0);
  1344. }
  1345.  
  1346. int main(int argc, char **argv) {
  1347.   seed = time(0);
  1348.   newgame();
  1349. #ifdef BOTH
  1350.   int i = 1;
  1351.   if (Fl::args(argc, argv, i, arg) < argc) {
  1352.     fprintf(stderr," -t : use VT100 display\n", Fl::help);
  1353.     exit(1);
  1354.   }
  1355.   if (!getenv("DISPLAY")) terminal = 1;
  1356.   if (!terminal)
  1357. #endif
  1358. #ifdef FLTK
  1359.     return FLTKmain(argc,argv);
  1360. #endif
  1361. #ifdef VT100
  1362.   return VT100main();
  1363. #endif
  1364. }
  1365.  
  1366. //
  1367. // End of "$Id: checkers.cxx,v 1.9.2.3 1999/08/09 14:38:40 mike Exp $".
  1368. //
  1369.